package bs.util.tool.commongui.plugins;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import org.apache.commons.codec.digest.DigestUtils;

import bs.util.tool.commongui.GuiJPanel;
import bs.util.tool.commongui.GuiUtils;
import bs.util.tool.commongui.utils.FileUtils;
import bs.util.tool.commongui.utils.SearchFileNameParams;

/**
 * 计算文件数字签名.
 */
public class FileDigitalSignature extends GuiJPanel {

	private static final long serialVersionUID = 1L;

	/**
	 * 文本/文件夹路径表单.
	 */
	private JTextField digitalPathTextField = new JTextField();
	/**
	 * 文本/文件夹路径选择.
	 */
	private JFileChooser digitalPath_Chooser = new JFileChooser();

	/**
	 * 是否计算MD5.
	 */
	private boolean ifDigitalMd5 = true;

	/**
	 * 是否计算SHA1.
	 */
	private boolean ifDigitalSha1 = false;

	/**
	 * 计算按钮.
	 */
	private JButton digitalButton;

	/**
	* 文件名包含字符表单.
	*/
	private JTextField fileNameContainsTextField;
	/**
	 * 文件名不包含字符表单.
	 */
	private JTextField fileNameNotContainsTextField;
	/**
	 * 文件名是否支持正则.
	 */
	private boolean fileNameSupportRegex = false;

	/**
	 * 计算结果文本域.
	 */
	private JTextArea resultTextArea = createJTextArea(GuiUtils.font14_un);

	public FileDigitalSignature() {

		// 主面板：边界布局，分North、Center两部分，North用于放置输入及条件控件，Center是放置计算结果输出
		setLayout(new BorderLayout());

		// 输入及条件Panel
		JPanel inputPanel = new JPanel(new GridLayout(2, 1));

		// 文本/文件夹表单、计算按钮Panel
		JPanel fileChooAndDetectPanel = new JPanel(new BorderLayout());
		// 文本/文件夹表单
		addJLabel(fileChooAndDetectPanel, "  文件/文件夹: ", GuiUtils.font14_cn, BorderLayout.WEST);
		JPanel fileChooPanel = new JPanel(new BorderLayout());
		fileChooPanel.add(new JPanel(), BorderLayout.NORTH);
		addJTextField(fileChooPanel, digitalPathTextField, GuiUtils.font14_un, BorderLayout.CENTER);
		fileChooPanel.add(new JPanel(), BorderLayout.SOUTH);
		fileChooAndDetectPanel.add(fileChooPanel, BorderLayout.CENTER);

		JPanel buttonFlowPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
		addJButton(buttonFlowPanel, "浏览", "", GuiUtils.font12_cn,
				buttonBrowseListener(digitalPath_Chooser, digitalPathTextField));
		// 计算按钮
		digitalButton = createJButton("计算", "", GuiUtils.font14b_cn);
		digitalButton.addMouseListener(new MouseListener() {
			public void mouseReleased(MouseEvent event) {
				String path = digitalPathTextField.getText().trim();
				File file = new File(path);
				if (!file.exists()) {
					showMessage("文件/文件夹不存在！", "警告", JOptionPane.WARNING_MESSAGE);
					return;
				}
				Map<String, Object> paramsMap = new HashMap<String, Object>();
				paramsMap.put("fileNameContainsText", fileNameContainsTextField.getText().trim());
				paramsMap.put("fileNameNotContainsText", fileNameNotContainsTextField.getText().trim());
				paramsMap.put("fileNameSupportRegex", fileNameSupportRegex);
				digitalButton.setEnabled(false);

				resultTextArea.setText("");
				try {
					if (!file.isDirectory()) {
						appendDigitalResult(resultTextArea, file, ifDigitalMd5, ifDigitalSha1);
					} else {
						List<File> files = new ArrayList<File>();
						FileUtils.loopDirectory(file, files, new SearchFileNameParams(paramsMap));
						for (File fFile : files) {
							appendDigitalResult(resultTextArea, fFile, ifDigitalMd5, ifDigitalSha1);
						}
						resultTextArea.append("\nDigital files: " + files.size());
					}
				} catch (NumberFormatException e) {
					showMessage("取样大小必须是正整数！", "警告", JOptionPane.WARNING_MESSAGE);
				} catch (IOException e) {
					showExceptionMessage(e);
				}
				digitalButton.setEnabled(true);
			}

			public void mousePressed(MouseEvent e) {
				resultTextArea.setText("");
			}

			public void mouseExited(MouseEvent e) {
			}

			public void mouseEntered(MouseEvent e) {
			}

			public void mouseClicked(MouseEvent e) {
			}
		});
		buttonFlowPanel.add(digitalButton);
		// 路径选择控件
		digitalPath_Chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); // 可选择文件/文件夹
		fileChooAndDetectPanel.add(buttonFlowPanel, BorderLayout.EAST);
		inputPanel.add(fileChooAndDetectPanel);

		// 高级条件Panel
		JPanel advancePanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
		addJLabel(advancePanel, " ", GuiUtils.font12_cn);
		// 是否计算MD5
		addJCheckBox(advancePanel, "MD5 ", true, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				ifDigitalMd5 = ((JCheckBox) event.getSource()).isSelected();
			}
		});
		// 是否计算SHA1
		addJCheckBox(advancePanel, "SHA1 ", false, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				ifDigitalSha1 = ((JCheckBox) event.getSource()).isSelected();
			}
		});
		// 文件名包含(不包含)字符
		addJLabel(advancePanel, "  文件名包含字符: ", GuiUtils.font14_cn);
		fileNameContainsTextField = new JTextField(16);
		addJTextField(advancePanel, fileNameContainsTextField, GuiUtils.font14_un);
		addJLabel(advancePanel, "  文件名不包含字符: ", GuiUtils.font14_cn);
		fileNameNotContainsTextField = new JTextField(16);
		addJTextField(advancePanel, fileNameNotContainsTextField, GuiUtils.font14_un);
		// 是否支持正则
		addJCheckBox(advancePanel, "支持正则", false, GuiUtils.font14_cn, new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				fileNameSupportRegex = ((JCheckBox) event.getSource()).isSelected();
			}
		});
		inputPanel.add(advancePanel);

		add(inputPanel, BorderLayout.NORTH);

		// 计算结果输出
		JPanel detectLogPanel = new JPanel(new BorderLayout());
		detectLogPanel.add(new JScrollPane(resultTextArea));
		add(detectLogPanel, BorderLayout.CENTER);
	}

	/**
	 * append计算文件数字签名结果.
	 */
	private void appendDigitalResult(JTextArea resultTextArea, File file, boolean ifDigitalMd5, boolean ifDigitalSha1)
			throws IOException {
		resultTextArea.append(file.getAbsolutePath());
		if (ifDigitalMd5) {
			resultTextArea.append("         MD5: " + digitalFileMd5(file));
		}
		if (ifDigitalSha1) {
			resultTextArea.append("         SHA1: " + digitalFileSha1(file));
		}
		resultTextArea.append("\n");
	}

	/**
	 * 计算文件数字签名-MD5.
	 */
	public static String digitalFileMd5(File file) throws IOException {
		return DigestUtils.md5Hex(new FileInputStream(file));
	}

	/**
	 * 计算文件数字签名-SHA1.
	 */
	public static String digitalFileSha1(File file) throws IOException {
		return DigestUtils.shaHex(new FileInputStream(file));
	}

}
